import { HashMap, HashSet } from '@kit.ArkTS';
import {
  EventCallback,
  EventMeta,
  EmitResult,
  ClearStickyOption,
  EventListenerOptions
} from './types/EventTypes';

/**
 * 事件分发器，负责事件的核心管理逻辑
 * 内部维护事件与监听器的映射关系，处理事件触发和粘性事件
 */
export class Dispatch {
  // 事件名到事件元数据集合的映射
  private eventMap = new HashMap<string, HashSet<EventMeta<any>>>();

  // 粘性事件存储，保存每个事件的最新参数
  private stickyEvents = new HashMap<string, any[]>();

  // 用于生成唯一标识，便于调试和去重
  private listenerId = 0;

  /**
   * 添加事件监听器
   * @param eventName 事件名称
   * @param callback 回调函数
   * @param options 监听选项
   * @returns 监听器唯一标识，用于移除监听器
   */
  addListener<T extends any[]>(
    eventName: string,
    callback: EventCallback<T>,
    options: EventListenerOptions = {}
  ): number {
    const {
      sticky = false,
      context = undefined,
      once = false
    } = options;

    // 获取或创建事件对应的监听器集合
    let listeners = this.eventMap.get(eventName);
    if (!listeners) {
      listeners = new HashSet<EventMeta<T>>();
      this.eventMap.set(eventName, listeners);
    }
    this.listenerId++;
    // 创建事件元数据
    const meta: EventMeta<T> = {
      callback,
      context,
      sticky,
      once,
      timestamp: Date.now(),
      listenerId: this.listenerId
    };

    // 添加监听器
    listeners.add(meta);

    // 如果是粘性事件且存在历史数据，立即触发一次
    if (sticky) {
      const stickyData = this.stickyEvents.get(eventName);
      if (stickyData) {
        this.invokeCallback(meta, stickyData).catch(err => {
          console.error(`[Dispatch] Sticky event callback error for ${eventName}:`, err);
        });
      }
    }

    return this.listenerId;
  }

  /**
   * 移除事件监听器
   * @param eventName 事件名称
   * @param callback 要移除的回调函数，如果不传则移除该事件的所有监听器
   * @returns 移除的监听器数量
   */
  removeListener<T extends any[]>(
    eventName: string,
    callback?: EventCallback<T>
  ): number {
    const listeners = this.eventMap.get(eventName);
    if (!listeners) {
      return 0;
    }

    let removedCount = 0;

    if (callback) {
      // 移除特定回调的监听器
      const toRemove: EventMeta<T>[] = [];
      listeners.forEach(meta => {
        if (meta.callback === callback) {
          toRemove.push(meta);
        }
      });

      toRemove.forEach(meta => {
        if (listeners.remove(meta)) {
          removedCount++;
        }
      });
    } else {
      // 移除该事件的所有监听器
      removedCount = listeners.length;
      listeners.clear();
    }

    // 如果事件没有监听器了，从映射中移除该事件
    if (listeners.isEmpty()) {
      this.eventMap.remove(eventName);
    }

    return removedCount;
  }

  /**
   * 根据监听器ID移除监听器（用于once等场景）
   * @param eventName 事件名称
   * @param listenerId 监听器ID
   * @returns 是否成功移除
   */
  removeListenerById(eventName: string, listenerId: number): boolean {
    const listeners = this.eventMap.get(eventName);
    if (!listeners) {
      return false;
    }

    let removed = false;
    const toRemove: EventMeta<any>[] = [];

    listeners.forEach(meta => {
      // 这里通过timestamp模拟ID匹配，实际实现可能需要额外存储ID
      if (meta?.listenerId === listenerId) {
        toRemove.push(meta);
        removed = true;
      }
    });

    toRemove.forEach(meta => listeners.remove(meta));

    if (listeners.isEmpty()) {
      this.eventMap.remove(eventName);
    }

    return removed;
  }

  /**
   * 触发事件
   * @param eventName 事件名称
   * @param args 事件参数
   * @returns 事件触发结果
   */
  async emit<T extends any[]>(eventName: string, ...args: T): Promise<EmitResult> {
    const result: EmitResult = {
      success: true,
      listenerCount: 0,
      errorCount: 0,
      errors: []
    };

    const listeners = this.eventMap.get(eventName);
    if (!listeners || listeners.isEmpty()) {
      return result;
    }

    // 保存当前监听器快照，避免在触发过程中因监听器变化导致问题
    const listenersSnapshot = Array.from(listeners.values());
    result.listenerCount = listenersSnapshot.length;

    // 存储粘性事件数据
    this.stickyEvents.set(eventName, args);

    // 并行执行所有监听器
    const promises = listenersSnapshot.map(meta =>
    this.invokeCallback(meta, args)
      .catch(error => {
        result.success = false;
        result.errorCount++;
        result.errors.push({ error, listener: meta.callback });
        return null;
      })
      .then(() => {
        // 如果是一次性监听器，执行后移除
        if (meta.once) {
          listeners.remove(meta);
        }
      })
    );

    // 等待所有监听器执行完成
    await Promise.all(promises);

    // 如果事件没有监听器了，从映射中移除该事件
    if (listeners.isEmpty()) {
      this.eventMap.remove(eventName);
    }

    return result;
  }

  /**
   * 清理粘性事件
   * @param option 清理选项
   */
  clearStickyEvents(option: ClearStickyOption = {}): void {
    const { eventName, force = false } = option;

    if (eventName) {
      this.stickyEvents.remove(eventName);
    } else if (force) {
      this.stickyEvents.clear();
    }
  }

  /**
   * 获取事件的监听器数量
   * @param eventName 事件名称
   * @returns 监听器数量，如果事件不存在则返回0
   */
  getListenerCount(eventName: string): number {
    const listeners = this.eventMap.get(eventName);
    return listeners ? listeners.length : 0;
  }

  /**
   * 检查事件是否有监听器
   * @param eventName 事件名称
   * @returns 如果事件有监听器则返回true，否则返回false
   */
  hasListeners(eventName: string): boolean {
    return this.getListenerCount(eventName) > 0;
  }

  /**
   * 获取所有注册的事件名称
   * @returns 事件名称数组
   */
  getEventNames(): string[] {
    return Array.from(this.eventMap.keys());
  }

  /**
   * 清空所有事件和监听器
   */
  clearAll(): void {
    this.eventMap.clear();
    this.stickyEvents.clear();
  }

  /**
   * 调用事件回调函数
   * @param meta 事件元数据
   * @param args 事件参数
   */
  private async invokeCallback<T extends any[]>(
    meta: EventMeta<T>,
    args: T
  ): Promise<void> {
    try {
      // 调用回调函数，绑定上下文
      const result = meta.callback.apply(meta.context, args);
      // 如果是Promise，等待其完成
      if (result instanceof Promise) {
        await result;
      }
    } catch (error) {
      console.error(`[Dispatch] Error invoking callback:`, error);
      throw error; // 重新抛出，让调用者处理
    }
  }
}
